﻿/*----------------------------------------------------------------
//  <copyright file="MailKitReceiver.cs" company="MicroCloud@151504200868">
//      Copyright © 2020-2024 MicroCloud Corporation, All rights reserved.
//  </copyright>
//  <site>https://gitee.com/chenmm123/microclouds</site>
//  <last-editor>cmm</last-editor>
//  <last-date>2024-03-04 14:40</last-date>
//----------------------------------------------------------------*/

using MailKit;
using MailKit.Net.Imap;
using MailKit.Net.Pop3;
using MimeKit;

namespace MicroCloud
{
    #region "MailKit邮件接收者"
    /// <summary>
    /// MailKit邮件接收者
    /// 详情：<see href="https://github.com/jstedfast/MailKit"/>
    /// </summary>
    public class MailKitReceiver : IEmailReceiver
    {
        //字段
        private readonly IServiceProvider _provider;
        private readonly ILogger<MailKitReceiver> _logger;
        private readonly MicroCloudOptions _options;

        #region "构造函数"
        #region "初始化一个MailKit邮件接收者 <see cref="MailKitReceiver"/> 的新实例"
        /// <summary>
        /// 初始化一个MailKit邮件接收者 <see cref="MailKitReceiver"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public MailKitReceiver(IServiceProvider provider)
        {
            _provider = provider;
            _logger = _provider.GetLogger<MailKitReceiver>();
            _options = _provider.GetMicroCloudOptions();
        }
        #endregion

        #endregion

        #region "方法"
        #region "接收邮件"
        /// <summary>
        /// 接收邮件
        /// </summary>
        /// <param name="options">邮件配置信息</param>
        /// <returns>邮件消息列表</returns>
        /// <exception cref="Exception">微云框架异常信息</exception>
        public virtual List<MimeMessage> ReceiveEmail(EmailReceiverOptions options = null)
        {
            var mailReceiver = options ?? (_options?.Email?.Receiver);
            if (mailReceiver == null || mailReceiver.Host == null || mailReceiver.Host.Contains("请替换"))
            {
                throw new Exception(I18N.T("邮件接收选项不存在，请在 appsettings.json 配置 MicroCloud:Email:Receiver 节点"));
            }
            var protocolType = mailReceiver.GetProtocolType();
            List<MimeMessage> messages = new();
            if (protocolType == EmailProtocolType.POP)
            {
                using var client = new Pop3Client();
                client.ServerCertificateValidationCallback = (s, c, h, e) => true;
                client.Connect(mailReceiver.Host, mailReceiver.Port, mailReceiver.EnableSsl);
                client.Authenticate(mailReceiver.UserName, mailReceiver.Password);
                for (int i = 0; i < client.Count; i++)
                {
                    var message = client.GetMessage(i);
                    //Console.WriteLine("Subject: {0}", message.Subject);
                    messages.Add(message);
                }
                client.Disconnect(true);
            }
            else
            {
                using var client = new ImapClient();
                client.ServerCertificateValidationCallback = (s, c, h, e) => true;
                client.Connect(mailReceiver.Host, mailReceiver.Port, mailReceiver.EnableSsl);
                client.Authenticate(mailReceiver.UserName, mailReceiver.Password);
                // The Inbox folder is always available on all IMAP servers...
                var inbox = client.Inbox;
                //var inbox = client.Inbox.Search(SearchQuery.NotSeen);
                inbox.Open(FolderAccess.ReadOnly);
                //Console.WriteLine("Total messages: {0}", inbox.Count);
                //Console.WriteLine("Recent messages: {0}", inbox.Recent);
                for (int i = 0; i < inbox.Count; i++)
                {
                    var message = inbox.GetMessage(i);
                    _logger.LogDebug("收取邮件 {subject} 完成", message.Subject);
                    //Console.WriteLine("Subject: {0}", message.Subject);
                    messages.Add(message);
                    //inbox.Store(i, new StoreFlagsRequest(StoreAction.Add, MessageFlags.Seen) { Silent = true });
                }

                //// 搜索Subject标题包含“MimeKit”或“MailKit”的邮件
                //var query = SearchQuery.SubjectContains("MimeKit").Or(SearchQuery.SubjectContains("MailKit"));
                //var uids = client.Inbox.Search(query);
                //// 获取搜索结果的摘要信息（我们需要UID和BODYSTRUCTURE每条消息，以便我们可以提取文本正文和附件）
                //var items = client.Inbox.Fetch(uids, MessageSummaryItems.UniqueId | MessageSummaryItems.BodyStructure);

                client.Disconnect(true);
            }
            //foreach (var message in messages)
            //{
            //    // IMessageSummary.TextBody是一个便利的属性，可以为我们找到“文本/纯文本”的正文部分
            //    var textBody = message.TextBody;
            //    var htmlBody = message.HtmlBody;

            //    // TextPart.Text是一个便利的属性，它解码内容并将结果转换为我们的字符串
            //    var text = textBody ?? htmlBody;

            //    // 现在遍历所有附件并将其保存到磁盘
            //    foreach (var attachment in message.Attachments)
            //    {
            //        // 像我们对内容所做的那样下载附件
            //        var entity = attachment;

            //        // 附件可以是message / rfc822部件或常规MIME部件
            //        if (entity is MessagePart messagePart)
            //        {
            //            var rfc822 = messagePart;

            //            //var path = Path.Combine(directory, attachment.PartSpecifier + ".eml");
            //            Stream stream = new MemoryStream();
            //            rfc822.Message.WriteTo(FormatOptions.Default, stream);
            //        }
            //        else
            //        {
            //            var part = (MimePart)entity;

            //            // 注意：这可能是空的，但大多数会指定一个文件名
            //            var fileName = part.FileName;
            //            Stream stream = new MemoryStream();
            //            part.Content.DecodeTo(stream);
            //        }
            //    }
            //}
            return messages;
        }
        #endregion

        #region "异步接收邮件"
        /// <summary>
        /// 异步接收邮件
        /// </summary>
        /// <param name="options">邮件配置信息</param>
        /// <returns>邮件消息列表</returns>
        /// <exception cref="Exception">微云框架异常信息</exception>
        public virtual async Task<List<MimeMessage>> ReceiveEmailAsync(EmailReceiverOptions options = null)
        {
            var mailReceiver = options ?? (_options?.Email?.Receiver);
            if (mailReceiver == null || mailReceiver.Host == null || mailReceiver.Host.Contains("请替换"))
            {
                throw new Exception(I18N.T("邮件接收选项不存在，请在 appsettings.json 配置 MicroCloud:Email:Receiver 节点"));
            }
            var protocolType = mailReceiver.GetProtocolType();
            List<MimeMessage> messages = new();
            if (protocolType == EmailProtocolType.POP)
            {
                using var client = new Pop3Client();
                client.ServerCertificateValidationCallback = (s, c, h, e) => true;
                await client.ConnectAsync(mailReceiver.Host, mailReceiver.Port, mailReceiver.EnableSsl);
                await client.AuthenticateAsync(mailReceiver.UserName, mailReceiver.Password);
                for (int i = 0; i < client.Count; i++)
                {
                    var message = client.GetMessage(i);
                    //Console.WriteLine("Subject: {0}", message.Subject);
                    messages.Add(message);
                }
                await client.DisconnectAsync(true);
            }
            else
            {
                using var client = new ImapClient();
                client.ServerCertificateValidationCallback = (s, c, h, e) => true;
                await client.ConnectAsync(mailReceiver.Host, mailReceiver.Port, mailReceiver.EnableSsl);
                await client.AuthenticateAsync(mailReceiver.UserName, mailReceiver.Password);
                // The Inbox folder is always available on all IMAP servers...
                var inbox = client.Inbox;
                //var inbox = client.Inbox.Search(SearchQuery.NotSeen);
                inbox.Open(FolderAccess.ReadOnly);

                //Console.WriteLine("Total messages: {0}", inbox.Count);
                //Console.WriteLine("Recent messages: {0}", inbox.Recent);

                for (int i = 0; i < inbox.Count; i++)
                {
                    var message = inbox.GetMessage(i);
                    _logger.LogDebug("收取邮件 {subject} 完成", message.Subject);
                    //Console.WriteLine("Subject: {0}", message.Subject);
                    messages.Add(message);
                }

                await client.DisconnectAsync(true);
            }
            return messages;
        }
        #endregion

        #endregion

    }
    #endregion

}
